package com.ljf.daily.makemoneydetail.domain.service;

import com.ljf.common.domain.service.BasisDomainService;
import com.ljf.common.exception.ServiceException;
import com.ljf.common.utils.CollectionUtil;
import com.ljf.common.utils.DateUtil;
import com.ljf.common.utils.EnumUtil;
import com.ljf.common.utils.StringUtil;
import com.ljf.daily.makemoneydetail.domain.entity.DailyDatMakeMoneyDetailImportData;
import com.ljf.daily.makemoneydetail.dto.command.DailyDatMakeMoneyDetailAccountAdjustCommand;
import com.ljf.daily.makemoneydetail.dto.command.DailyDatMakeMoneyDetailCommand;
import com.ljf.daily.makemoneydetail.dto.command.DailyDatMakeMoneyDetailImportDataCommand;
import com.ljf.daily.makemoneydetail.dto.command.DailyDatMakeMoneyDetailTemplateImportCommand;
import com.ljf.daily.makemoneydetail.vo.DailyDatMakeMoneyDetailImportDataVO;
import com.ljf.daily.makemoneydetail.vo.DailyDatMakeMoneyDetailVO;
import com.ljf.daily.makemoneysoftware.enums.DailyDatAccountAdjustSoftwareTypeEnum;
import com.ljf.daily.makemoneydetail.enums.DailyDatMakeMoneyDetailTypeEnum;
import com.ljf.daily.makemoneysoftware.vo.DailyDatAccountAdjustSoftwareVO;
import com.ljf.daily.softwareautorecord.enums.DailyDatSoftwareAutoRecordAmountHistoryEnum;
import com.ljf.daily.makemoneysoftware.enums.PhoneEnum;
import com.ljf.daily.makemoneydetail.domain.repository.DailyDatMakeMoneyDetailRepository;
import com.ljf.daily.makemoneydetail.dto.query.DailyDatMakeMoneyDetailQuery;
import com.ljf.daily.makemoneysoftware.domain.repository.DailyDatAccountAdjustSoftwareRepository;
import com.ljf.daily.makemoneysoftware.domain.repository.DailyDatMakeMoneySoftwareRepository;
import com.ljf.daily.makemoneysoftware.dto.query.DailyDatAccountAdjustSoftwareQuery;
import com.ljf.daily.makemoneysoftware.dto.query.DailyDatMakeMoneySoftwareQuery;
import com.ljf.daily.makemoneysoftware.model.DailyDatMakeMoneySoftware;
import com.ljf.daily.makemoneysoftware.vo.DailyDatMakeMoneySoftwareVO;
import com.ljf.daily.makemoneydetail.model.DailyDatMakeMoneyDetail;
import com.ljf.daily.softwareautorecord.model.DailyDatSoftwareAutoWithdrawal;
import com.ljf.daily.softwareautorecord.domain.repository.DailyDatSoftwareAutoRecordRepository;
import com.ljf.daily.softwareautorecord.domain.repository.DailyDatSoftwareAutoWithdrawalRepository;
import com.ljf.daily.softwareautorecord.dto.query.DailyDatSoftwareAutoRecordQuery;
import com.ljf.daily.softwareautorecord.dto.query.DailyDatSoftwareAutoWithdrawalQuery;
import com.ljf.daily.softwareautorecord.vo.DailyDatSoftwareAutoRecordVO;
import com.ljf.daily.softwareautorecord.vo.DailyDatSoftwareAutoWithdrawalVO;
import com.ljf.finance.domain.repository.FinanceDatVirtualAccountRepository;
import com.ljf.finance.dto.query.FinanceDatVirtualAccountQuery;
import com.ljf.finance.enums.FinanceDatVirtualAccountCommonUsedEnum;
import com.ljf.finance.model.FinanceDatVirtualAccount;
import com.ljf.finance.vo.FinanceDatVirtualAccountVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 赚钱明细记录  领域服务
 *
 * @author LJF
 * @since 2024-01-25
 */
@Component
@AllArgsConstructor
public class DailyDatMakeMoneyDetailDomainService extends BasisDomainService<DailyDatMakeMoneyDetailRepository, DailyDatMakeMoneyDetailQuery, DailyDatMakeMoneyDetailVO, DailyDatMakeMoneyDetail, DailyDatMakeMoneyDetailCommand> {

    private final DailyDatMakeMoneySoftwareRepository softwareRepository;
    private final FinanceDatVirtualAccountRepository financeDatVirtualAccountRepository;
    private final DailyDatAccountAdjustSoftwareRepository accountAdjustSoftwareRepository;
    private final DailyDatSoftwareAutoWithdrawalRepository softwareAutoWithdrawalRepository;
    private final DailyDatSoftwareAutoRecordRepository softwareAutoRecordRepository;

    /**
     * 导入数据接口
     *
     * @param command
     * @param resultList
     * @return
     * @throws ServiceException
     */
    public int importData(DailyDatMakeMoneyDetailImportDataCommand command, List<DailyDatMakeMoneyDetailImportDataVO> resultList) throws ServiceException {
        Date currentDate = null;
        List<DailyDatMakeMoneyDetailImportData> dataList = new ArrayList<>();
        int index = -1;
        for (String data : command.getDataList()) {
            if (StringUtil.isEmpty(data) || "#接龙".equals(data)) {
                continue;
            }
            try {
                currentDate = this.analysisOneLineImportDate(currentDate, data);
                index = this.analysisOneLineImportData(currentDate, data, dataList);
            }
            catch (ServiceException e) {
                throw new ServiceException(String.format("导入数据异常:第%s行出现错误：[%s]", (index + 1), e.getMessage()));
            }
        }
        this.checkAndFillImportData(dataList);
        return this.saveAndReturnReport(dataList, resultList);
    }

    /**
     * 新增
     *
     * @param command
     * @return
     * @throws ServiceException
     */
    @Override
    public DailyDatMakeMoneyDetail add(DailyDatMakeMoneyDetailCommand command) throws ServiceException {
        DailyDatMakeMoneyDetail model = DailyDatMakeMoneyDetail.builder()
                .softwareCode(command.getSoftwareCode())
                .withdrawalCount(command.getWithdrawalCount())
                .belongDate(command.getBelongDate())
                .remark(command.getRemark())
                .type(DailyDatMakeMoneyDetailTypeEnum.ADD.getCode())
                .build();
        List<DailyDatMakeMoneyDetail> modelList = new ArrayList<>();
        modelList.add(model);
        this.handleInsertMakeMoneyDetail(modelList);
        return model;
    }

    /**
     * 账户调整接口
     *
     * @param command
     * @throws ServiceException
     */
    public void accountAdjust(DailyDatMakeMoneyDetailAccountAdjustCommand command) throws ServiceException {
        FinanceDatVirtualAccountVO account = financeDatVirtualAccountRepository.selectOne(
                FinanceDatVirtualAccountQuery.builder().code(command.getAccountCode()).build()
        );
        if (account == null) {
            throw new ServiceException("账户调整异常:账户不存在");
        }
        Integer type;
        BigDecimal withdrawalCount;
        if (account.getAmount().compareTo(command.getAmount()) == 0) {
            throw new ServiceException("账户调整异常:金额相同，无需调整");
        }
        else if (account.getAmount().compareTo(command.getAmount()) > 0) {
            type = DailyDatAccountAdjustSoftwareTypeEnum.PAYMENT_OUT.getCode();
            withdrawalCount = (command.getAmount().subtract(account.getAmount()));
        }
        else {
            type = DailyDatAccountAdjustSoftwareTypeEnum.ACCOUNT_ENTRY.getCode();
            withdrawalCount = (command.getAmount().subtract(account.getAmount()));
        }
        DailyDatAccountAdjustSoftwareVO adjustSoftware = accountAdjustSoftwareRepository.selectOne(
                DailyDatAccountAdjustSoftwareQuery.builder().accountCode(command.getAccountCode()).type(type).build(),
                "调整软件编码配置异常:未到对应的调整软件编码",
                "调整软件编码配置异常:存在多条数据"
        );
        DailyDatMakeMoneySoftwareVO makeMoneySoftware = softwareRepository.selectOne(
                DailyDatMakeMoneySoftwareQuery.builder().code(adjustSoftware.getSoftwareCode()).build(),
                "调整软件编码配置异常:软件编码不存在",
                "软件编码配置异常:存在多条数据"
        );
        if (!StringUtil.equals(makeMoneySoftware.getAccountCode(), command.getAccountCode())) {
            throw new ServiceException("调整软件编码配置异常:涉及影响账户不一致");
        }
        DailyDatMakeMoneyDetail model = DailyDatMakeMoneyDetail.builder()
                .softwareCode(adjustSoftware.getSoftwareCode())
                .withdrawalCount(withdrawalCount)
                .belongDate(command.getBelongDate())
                .remark(command.getRemark())
                .type(DailyDatMakeMoneyDetailTypeEnum.ADJUST.getCode())
                .build();
        List<DailyDatMakeMoneyDetail> modelList = new ArrayList<>();
        modelList.add(model);
        this.handleInsertMakeMoneyDetail(modelList);
    }

    @Override
    public boolean deleteBatch(List<Long> ids) throws ServiceException {
        List<DailyDatMakeMoneyDetailVO> detailList = repository.selectListByIds(ids);
        if (CollectionUtil.isEmpty(detailList)) {
            throw new ServiceException("赚钱明细批量删除异常:数据不存在");
        }
        this.handleDeleteMakeMoneyDetail(ids);
        return true;
    }

    /**
     * 模板导入
     *
     * @param command
     * @throws ServiceException
     */
    public void templateImport(DailyDatMakeMoneyDetailTemplateImportCommand command) throws ServiceException {
        List<DailyDatMakeMoneyDetailCommand> commandList = command.getDataList();
        List<DailyDatMakeMoneyDetail> modelList = new ArrayList<>();
        List<String> softwareCodeList = commandList.stream().map(DailyDatMakeMoneyDetailCommand::getSoftwareCode)
                .distinct().collect(Collectors.toList());
        List<DailyDatMakeMoneySoftwareVO> softwareList = softwareRepository.selectList(
                DailyDatMakeMoneySoftwareQuery.builder().codeList(softwareCodeList).build()
        );
        Map<String, String> softwareToAccountMap = softwareList.stream().collect(
                Collectors.toMap(DailyDatMakeMoneySoftwareVO::getCode, DailyDatMakeMoneySoftwareVO::getAccountCode, (a, b) -> a)
        );
        Map<String, BigDecimal> accountMap = new HashMap<>();
        Map<String, BigDecimal> withdrawalMap = new HashMap<>();
        for (DailyDatMakeMoneyDetailCommand dataCommand : commandList) {
            if (StringUtil.isEmpty(dataCommand.getWithdrawalCountList())) {
                continue;
            }
            for (String withdrawalCount : dataCommand.getWithdrawalCountList().split(" ")) {
                BigDecimal decimal = new BigDecimal(withdrawalCount);
                if (BigDecimal.ZERO.compareTo(decimal) == 0) {
                    continue;
                }
                withdrawalMap.put(dataCommand.getSoftwareAutoCode(), decimal);
                for (int i = 0; i < command.getExeNumber(); i++) {
                    modelList.add(
                            DailyDatMakeMoneyDetail.builder()
                                    .softwareCode(dataCommand.getSoftwareCode())
                                    .withdrawalCount(decimal)
                                    .belongDate(dataCommand.getBelongDate())
                                    .remark(dataCommand.getRemark())
                                    .type(DailyDatMakeMoneyDetailTypeEnum.AUTO_RECORD.getCode())
                                    .build()
                    );
                }
                if (!softwareToAccountMap.containsKey(dataCommand.getSoftwareCode())) {
                    throw new ServiceException("模板导入执行异常:" + dataCommand.getSoftwareCode() + "不存在");
                }
                String accountCode = softwareToAccountMap.get(dataCommand.getSoftwareCode());
                accountMap.put(accountCode, accountMap.getOrDefault(accountCode, BigDecimal.ZERO).add(decimal));
            }
        }
        this.handleUpdateWithdrawal(withdrawalMap);
        List<FinanceDatVirtualAccountVO> accountList = financeDatVirtualAccountRepository.selectList(
                FinanceDatVirtualAccountQuery.builder().codeList(new ArrayList<>(accountMap.keySet())).build()
        );
        Map<String, FinanceDatVirtualAccountVO> accountModelMap = accountList.stream().collect(
                Collectors.toMap(FinanceDatVirtualAccount::getCode, Function.identity(), (a, b) -> a)
        );
        for (Map.Entry<String, BigDecimal> entry : accountMap.entrySet()) {
            if (!accountModelMap.containsKey(entry.getKey())) {
                throw new ServiceException("模板导入执行异常:" + entry.getKey() + "不存在");
            }
            accountModelMap.get(entry.getKey()).setAmount(accountModelMap.get(entry.getKey()).getAmount().add(entry.getValue()));
        }
        this.handleInsertMakeMoneyDetail(modelList);
    }

    /**
     * 查询
     *
     * @param softwareCode
     * @param belongDate
     * @return
     * @throws ServiceException
     */
    public List<DailyDatMakeMoneyDetailVO> queryList(String softwareCode, Date belongDate) throws ServiceException {
        return repository.selectList(
                DailyDatMakeMoneyDetailQuery.builder()
                        .softwareCode(softwareCode)
                        .belongDate(belongDate)
                        .build()
        );
    }

    /**
     * 处理赚钱明细-执行
     *
     * @param insertList
     * @param deleteIds
     * @throws ServiceException
     */
    public synchronized void execHandleMakeMoneyDetail(List<DailyDatMakeMoneyDetail> insertList, List<Long> deleteIds) throws ServiceException {
        List<DailyDatMakeMoneyDetail> modelList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(insertList)) {
            modelList.addAll(insertList);
            repository.insertBatch(insertList);
        }
        if (CollectionUtil.isNotEmpty(deleteIds)) {
            List<DailyDatMakeMoneyDetailVO> detailList = repository.selectListByIds(deleteIds);
            for (DailyDatMakeMoneyDetailVO detail : detailList) {
                detail.setWithdrawalCount(detail.getWithdrawalCount().multiply(BigDecimal.valueOf(-1)));
            }
            modelList.addAll(detailList);
            repository.deleteBatchByIds(deleteIds);
        }
        List<String> softwareCodeList = modelList.stream()
                .map(DailyDatMakeMoneyDetail::getSoftwareCode).distinct().collect(Collectors.toList());
        int softwareCodeCount = softwareRepository.count(
                DailyDatMakeMoneySoftwareQuery.builder().codeList(softwareCodeList).build()
        );
        if (softwareCodeList.size() != softwareCodeCount) {
            throw new ServiceException("批处理明细异常:归属赚钱软件编码不存在");
        }
        List<DailyDatMakeMoneySoftwareVO> softwareList = softwareRepository.selectList(
                DailyDatMakeMoneySoftwareQuery.builder().codeList(softwareCodeList).build()
        );
        Map<String, String> softwareMap = softwareList.stream().collect(
                Collectors.toMap(DailyDatMakeMoneySoftwareVO::getCode, DailyDatMakeMoneySoftwareVO::getAccountCode, (a, b) -> a)
        );
        List<String> financeCodeList = new ArrayList<>(softwareMap.values()).stream().distinct().collect(Collectors.toList());
        int financeCount = financeDatVirtualAccountRepository.count(
                FinanceDatVirtualAccountQuery.builder().codeList(financeCodeList).build()
        );
        if (financeCodeList.size() != financeCount) {
            throw new ServiceException("批处理明细异常:归属赚钱软件对应的账户不存在");
        }
        Map<String, BigDecimal> changeAccountMap = new HashMap<>();
        for (DailyDatMakeMoneyDetail model : modelList) {
            String financeCode = softwareMap.getOrDefault(model.getSoftwareCode(), "");
            changeAccountMap.put(financeCode, changeAccountMap.getOrDefault(financeCode, BigDecimal.ZERO).add(model.getWithdrawalCount()));
        }
        List<FinanceDatVirtualAccountVO> accountList = financeDatVirtualAccountRepository.selectList(
                FinanceDatVirtualAccountQuery.builder().codeList(financeCodeList).build()
        );
        List<FinanceDatVirtualAccount> financeUpdateModelList = new ArrayList<>();
        for (FinanceDatVirtualAccountVO account : accountList) {
            financeUpdateModelList.add(
                    FinanceDatVirtualAccount.builder()
                            .id(account.getId())
                            .amount(account.getAmount().add(changeAccountMap.get(account.getCode())))
                            .build()
            );
        }
        financeDatVirtualAccountRepository.updateBatchByIds(financeUpdateModelList);
    }

    /**
     * 更新自动记录金额
     *
     * @param withdrawalMap
     * @throws ServiceException
     */
    private void handleUpdateWithdrawal(Map<String, BigDecimal> withdrawalMap) throws ServiceException {
        List<DailyDatSoftwareAutoRecordVO> autoRecordList = softwareAutoRecordRepository.selectList(
                DailyDatSoftwareAutoRecordQuery.builder()
                        .codeList(new ArrayList<>(withdrawalMap.keySet()))
                        .amountHistory(DailyDatSoftwareAutoRecordAmountHistoryEnum.LATEST_VALUE.getCode())
                        .build()
        );
        if (CollectionUtil.isNotEmpty(autoRecordList)) {
            List<String> codeList = autoRecordList.stream()
                    .map(DailyDatSoftwareAutoRecordVO::getCode).distinct().collect(Collectors.toList());
            List<DailyDatSoftwareAutoWithdrawalVO> autoWithdrawalList = softwareAutoWithdrawalRepository.selectList(
                    DailyDatSoftwareAutoWithdrawalQuery.builder()
                            .softwareAutoCodeList(codeList)
                            .build()
            );
            Map<String, Long> codeToIdMap = autoWithdrawalList.stream().collect(Collectors.toMap(
                    DailyDatSoftwareAutoWithdrawalVO::getSoftwareAutoCode,
                    DailyDatSoftwareAutoWithdrawalVO::getId,
                    (a, b) -> a)
            );
            List<DailyDatSoftwareAutoWithdrawal> withdrawalList = new ArrayList<>();
            for (DailyDatSoftwareAutoRecordVO record : autoRecordList) {
                withdrawalList.add(
                        DailyDatSoftwareAutoWithdrawal.builder()
                                .id(codeToIdMap.get(record.getCode()))
                                .withdrawalCount(withdrawalMap.get(record.getCode()))
                                .build()
                );
            }
            softwareAutoWithdrawalRepository.updateBatchByIds(withdrawalList);
        }
    }

    /**
     * 保存并返回报表
     *
     * @param dataList
     * @param resultList
     * @return
     * @throws ServiceException
     */
    private int saveAndReturnReport(List<DailyDatMakeMoneyDetailImportData> dataList, List<DailyDatMakeMoneyDetailImportDataVO> resultList) throws ServiceException {
        List<FinanceDatVirtualAccountVO> accountList = financeDatVirtualAccountRepository.selectList(
                FinanceDatVirtualAccountQuery.builder().commonUsed(FinanceDatVirtualAccountCommonUsedEnum.TURE.getCode()).build()
        );
        Map<String, FinanceDatVirtualAccountVO> resultMap = accountList.stream().collect(Collectors.toMap(FinanceDatVirtualAccount::getCode, Function.identity(), (a, b) -> a));
        Map<String, BigDecimal> changeAmountMap = new HashMap<>();
        List<DailyDatMakeMoneyDetail> modelList = new ArrayList<>();
        int count = 0;
        for (DailyDatMakeMoneyDetailImportData data : dataList) {
            modelList.add(
                    DailyDatMakeMoneyDetail.builder()
                            .softwareCode(data.getSoftwareCode())
                            .withdrawalCount(data.getAmount())
                            .belongDate(data.getBelongDate())
                            .remark("批量导入")
                            .type(DailyDatMakeMoneyDetailTypeEnum.ADD.getCode())
                            .build()
            );
            count++;
            if (!resultMap.containsKey(data.getVirtualAccountCode())) {
                throw new ServiceException(String.format("导入数据异常:第%s行出现错误-账户[%s]不存在", data.getIndex(), data.getVirtualAccountCode()));
            }
            FinanceDatVirtualAccountVO account = resultMap.get(data.getVirtualAccountCode());
            account.setAmount(account.getAmount().add(data.getAmount()));
            changeAmountMap.put(data.getVirtualAccountCode(), changeAmountMap.getOrDefault(data.getVirtualAccountCode(), BigDecimal.ZERO).add(data.getAmount()));
        }
        for (FinanceDatVirtualAccountVO account : accountList) {
            resultList.add(
                    DailyDatMakeMoneyDetailImportDataVO.builder()
                            .virtualAccountCode(account.getCode())
                            .virtualAccountName(account.getName())
                            .virtualAccountAmount(account.getAmount())
                            .virtualAccountChangeValue(changeAmountMap.getOrDefault(account.getCode(), BigDecimal.ZERO))
                            .build()
            );
        }
        this.handleInsertMakeMoneyDetail(modelList);
        return count;
    }

    /**
     * 处理赚钱明细-删除
     *
     * @param deleteIds
     * @throws ServiceException
     */
    private void handleDeleteMakeMoneyDetail(List<Long> deleteIds) throws ServiceException {
        if (CollectionUtil.isEmpty(deleteIds)) {
            return;
        }
        if (deleteIds.size() != repository.countByIds(deleteIds)) {
            throw new ServiceException("批处理明细异常:部分数据不存在, 请刷新后重试");
        }
        this.execHandleMakeMoneyDetail(Collections.emptyList(), deleteIds);
    }

    /**
     * 处理赚钱明细-新增
     *
     * @param insertList
     * @throws ServiceException
     */
    private void handleInsertMakeMoneyDetail(List<DailyDatMakeMoneyDetail> insertList) throws ServiceException {
        if (CollectionUtil.isEmpty(insertList)) {
            return;
        }
        if (insertList.stream().anyMatch(one -> StringUtil.isEmpty(one.getSoftwareCode()))) {
            throw new ServiceException("批处理明细异常:归属赚钱软件编码存在空值");
        }
        if (insertList.stream().anyMatch(one -> one.getWithdrawalCount() == null)) {
            throw new ServiceException("批处理明细异常:提现统计存在空值");
        }
        if (insertList.stream().anyMatch(one -> one.getWithdrawalCount().compareTo(BigDecimal.ZERO) == 0)) {
            throw new ServiceException("批处理明细异常:提现统计存在0值");
        }
        if (insertList.stream().anyMatch(one -> one.getBelongDate() == null)) {
            throw new ServiceException("批处理明细异常:归属时间存在空值");
        }
        if (insertList.stream().anyMatch(one -> StringUtil.isNotEmpty(one.getRemark()) && one.getRemark().length() > 20)) {
            throw new ServiceException("批处理明细异常:备注存在过长记录");
        }
        Map<Integer, String> typeMap = EnumUtil.getCodeToNameMap(DailyDatMakeMoneyDetailTypeEnum.values());
        if (insertList.stream().anyMatch(one -> one.getType() == null || !typeMap.containsKey(one.getType()))) {
            throw new ServiceException("批处理明细异常:类型存在空值或者未配置记录");
        }
        this.execHandleMakeMoneyDetail(insertList, Collections.emptyList());
    }

    /**
     * 检查并填充导入数据
     *
     * @param dataList
     * @throws ServiceException
     */
    private void checkAndFillImportData(List<DailyDatMakeMoneyDetailImportData> dataList) throws ServiceException {
        if (CollectionUtil.isEmpty(dataList)) {
            throw new ServiceException("导入数据异常:请输入数据");
        }
        DailyDatMakeMoneyDetailImportData softwareErrorData = dataList.stream().filter(one -> one.getSoftwareName().length() <= 3).findFirst().orElse(null);
        if (softwareErrorData != null) {
            throw new ServiceException(String.format("导入数据异常:第%s行出现错误-异常软件[%s]", softwareErrorData.getIndex(), softwareErrorData.getSoftwareName()));
        }
        Map<String, String> phoneMap = new HashMap<>();
        for (PhoneEnum value : PhoneEnum.values()) {
            phoneMap.put(value.getName().substring(0, 3), value.getName());
        }
        List<String> softwarePhoneList = dataList.stream().map(one -> one.getSoftwareName().substring(one.getSoftwareName().length() - 3)).distinct().collect(Collectors.toList());
        Map<String, Integer> softwarePhoneMap = dataList.stream()
                .collect(Collectors.toMap(one -> one.getSoftwareName().substring(one.getSoftwareName().length() - 3), DailyDatMakeMoneyDetailImportData::getIndex, (a, b) -> a));
        List<String> softwareActualPhoneList = new ArrayList<>();
        for (String phone : softwarePhoneList) {
            if (!phoneMap.containsKey(phone)) {
                throw new ServiceException(String.format("导入数据异常:第%s行出现错误-异常软件手机号[%s]", softwarePhoneMap.get(phone), phone));
            }
            softwareActualPhoneList.add(phoneMap.get(phone));
        }
        List<String> softwareNameList = dataList.stream().map(one -> one.getSoftwareName().substring(0, one.getSoftwareName().length() - 3)).distinct().collect(Collectors.toList());
        List<String> virtualAccountNameList = dataList.stream().map(DailyDatMakeMoneyDetailImportData::getVirtualAccountName).distinct().collect(Collectors.toList());
        List<DailyDatMakeMoneySoftwareVO> softwareList = softwareRepository.selectList(
                DailyDatMakeMoneySoftwareQuery.builder()
                        .registerPhoneList(softwareActualPhoneList)
                        .nameList(softwareNameList)
                        .build()
        );
        if (CollectionUtil.isEmpty(softwareList)) {
            throw new ServiceException("导入数据异常:所有软件均未找到");
        }
        Map<String, String> softwareNameToCodeMap = new HashMap<>();
        Map<String, String> softwareNameToAccountMap = new HashMap<>();
        for (DailyDatMakeMoneySoftwareVO software : softwareList) {
            if (StringUtil.isEmpty(software.getRegisterPhone()) || software.getRegisterPhone().length() < 3) {
                throw new ServiceException(String.format("导入数据异常:编码为[%s]的软件注册手机数据存在问题", software.getCode()));
            }
            softwareNameToCodeMap.put(software.getName() + software.getRegisterPhone().substring(0, 3), software.getCode());
            softwareNameToAccountMap.put(software.getName() + software.getRegisterPhone().substring(0, 3), software.getAccountCode());
        }
        List<FinanceDatVirtualAccountVO> accountList = financeDatVirtualAccountRepository.selectList(
                FinanceDatVirtualAccountQuery.builder()
                        .shortNameList(virtualAccountNameList)
                        .build()
        );
        if (CollectionUtil.isEmpty(accountList)) {
            throw new ServiceException("导入数据异常:所有账户均未找到");
        }
        Map<String, String> accountNameToCodeMap = accountList.stream().collect(Collectors.toMap(FinanceDatVirtualAccount::getShortName, FinanceDatVirtualAccount::getCode, (a, b) -> a));
        for (DailyDatMakeMoneyDetailImportData data : dataList) {
            if (!softwareNameToCodeMap.containsKey(data.getSoftwareName())) {
                throw new ServiceException(String.format("导入数据异常:第%s行出现错误-异常软件[%s]", data.getIndex(), data.getSoftwareName()));
            }
            if (!accountNameToCodeMap.containsKey(data.getVirtualAccountName())) {
                throw new ServiceException(String.format("导入数据异常:第%s行出现错误-异常账户[%s]", data.getIndex(), data.getVirtualAccountName()));
            }
            data.setSoftwareCode(softwareNameToCodeMap.get(data.getSoftwareName()));
            data.setVirtualAccountCode(softwareNameToAccountMap.get(data.getSoftwareName()));
            if (!StringUtil.equals(data.getVirtualAccountCode(), accountNameToCodeMap.get(data.getVirtualAccountName()))) {
                throw new ServiceException(String.format("导入数据异常:第%s行出现错误-目标账户[%s]异常，请重新确认", data.getIndex(), data.getVirtualAccountName()));
            }
        }
    }

    /**
     * 解析一行的导入时间
     *
     * @param currentDate
     * @param line
     * @return
     * @throws ServiceException
     */
    private Date analysisOneLineImportDate(Date currentDate, String line) throws ServiceException {
        if (line.length() < 10) {
            return null;
        }
        if (currentDate == null) {
            return DateUtil.parseCommonDate(line.substring(0, 10), "yyyy/MM/dd");
        }
        if (line.substring(line.indexOf(".") + 1).trim().split(" ").length < 3) {
            return DateUtil.parseCommonDate(line.substring(0, 10), "yyyy/MM/dd");
        }
        return currentDate;
    }

    /**
     * 解析一行的导入数据
     *
     * @param currentDate
     * @param line
     * @param dataList
     * @return
     * @throws ServiceException
     */
    private int analysisOneLineImportData(Date currentDate, String line, List<DailyDatMakeMoneyDetailImportData> dataList) throws ServiceException {
        if (currentDate == null || StringUtil.isEmpty(line)) {
            return -1;
        }
        String[] split = line.substring(line.indexOf(".") + 1).trim().split(" ");
        if (split.length < 3) {
            return -1;
        }
        int index = Integer.parseInt(line.substring(0, line.indexOf(".")));
        for (int i = 2; i < split.length; i++) {
            dataList.add(
                    DailyDatMakeMoneyDetailImportData.builder()
                            .index(index)
                            .softwareName(split[0])
                            .virtualAccountName(split[1])
                            .amount(new BigDecimal(split[i]))
                            .belongDate(currentDate)
                            .build()
            );
        }
        return index;
    }

}
